﻿#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <functional>
#include <QObject>
#include <QPluginLoader>
#include "PluginConstant.h"

#include "PluginMajorVersion.h"
#include "QtWidgets/qwidget.h"

#if defined(PLUGINCORE_LIBRARY)
#define PLUGINCORE_EXPORT Q_DECL_EXPORT
#else
#define PLUGINCORE_EXPORT Q_DECL_IMPORT
#endif

class PluginInterface;


struct PluginInfo
{
    QJsonObject metaData;
    QPluginLoader *pluginLoader;
    QString filePath;
    QString name;
    bool checkSuccess=false; // false校验失败。  true 校验成功。
    QString checkInfo;//校验信息，版本不一致！签名不正确！  未发现问题！。
    PluginInterface *plugin;
    PluginInfo(QJsonObject metaDataA,
               QPluginLoader *pluginLoaderA,
               QString pluginFilePath,
               QString pluginName,
               PluginInterface *pluginA)
    {
        metaData=metaDataA;
        pluginLoader=pluginLoaderA;
        filePath=pluginFilePath;
        name=pluginName;
        plugin=pluginA;
    }
};

enum WidgetShowType
{
    ST_NONE,
    ST_WIDGET,
    ST_POPUP,
    ST_DOCK,
};
struct PluginWidgetInfo
{
public:
    WidgetShowType showType = ST_DOCK;
    int origWidth;
    int origHeight;
    QWidget *widget;
    QString objectName;
    QString description;
    PluginWidgetInfo(QWidget *w){
        widget =w;
        origWidth=widget->width();
        origHeight=widget->height();
        objectName=widget->objectName();
        description=widget->objectName();
    }
    PluginWidgetInfo(QWidget *w,QString desc){
        widget =w;
        origWidth=widget->width();
        origHeight=widget->height();
        objectName=widget->objectName();
        description=desc;
    }
    PluginWidgetInfo(WidgetShowType type, QWidget *w,QString desc){
        new (this) PluginWidgetInfo(w,desc);
        showType =type;
    }

    PluginWidgetInfo(){}
};


class PluginLoader;
class PLUGINCORE_EXPORT  PluginInterface:public QObject
{
    Q_OBJECT

public:


    const uint majorVersion=PluginMajorVersion;  //插件大版本，跟随主程序统一变更

    QString name;//pluginloader赋值
    QHash<QString,PluginWidgetInfo*> widgetMap;
    QHash<QString,std::function<void(bool)>> actionMap;
    QHash<QString,void *> functionMap;
    PluginLoader *pluginLoader=0;

    QWidget *getMainWin();
public:
    virtual ~PluginInterface() {}

public:

    virtual void loadWidget(){};//创建widget，供外部嵌入
    virtual void exposeAction(){};//暴露菜单action（function(bool)），供外部(主窗体)创建菜单（调用）
    virtual void exposeFunction(){};//暴露function(函数指针)，供外部调用
    virtual void initMainWin(){};
    bool isInited() { return inited; }
    virtual bool init(PluginLoader* loader)
    {   pluginLoader=loader;
        if(inited)return true;
        loadWidget();exposeAction();exposeFunction();initMainWin(); inited=true;return true; }

    virtual bool unload(){return true;}
    virtual bool isUnloadable() {if(!inited)return true; return unloadable; }//如果插件未初始化，则可以直接卸载
    
    //用于系统插件，即，已知系统设计开发时，就已经规定好了固定的Signal、receiver
    void connectX(const char *pszSignal,QObject *receiver, const char *pszSlot){connect(this, pszSignal, receiver, pszSlot);}
    void disconnectX(const char *pszSignal,QObject *receiver, const char *pszSlot){disconnect(this, pszSignal, receiver, pszSlot);}

    virtual int processMsg(int ,void*)=0;//用于单点，manager调用指定插件处理消息

protected:

    bool inited=false;
    bool unloadable=false;//是否允许动态卸载  如果插件里的资源被外部程序占用，比如，插件的某个widget给嵌入到主程序，那么在主程序释放插件的widget之前，是不允许卸载插件的。
signals:
    int sig_msg(int signal,void* userData);
    int sig_plugin(QVariant arg_in, QVariant &arg_out);

public slots:
    virtual int slot_msg(int ,void* ) { return 0; }//用于manager群发给所有插件，插件接收后处理
    virtual int slot_plugin(QVariant arg_in, QVariant &arg_out) { Q_UNUSED(arg_in);Q_UNUSED(arg_out);return 0; }

};
#define PluginInterface_iid "stone.QtPluginsManagerBus.PluginInterface"

Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)



#endif // PLUGININTERFACE_H
